#include <algorithm>

using namespace std;

// 给你两个 非空 的链表，表示两个非负的整数
// 它们每位数字都是按照 逆序 的方式存储的，并且每个节点只能存储 一位 数字
// 请你将两个数相加，并以相同形式返回一个表示和的链表。
// 你可以假设除了数字 0 之外，这两个数都不会以 0 开头
// 测试链接：https://leetcode.cn/problems/add-two-numbers/

// 不要提交这个类
struct ListNode 
{
    int val;
    ListNode *next;
    ListNode() : val(0), next(nullptr) {}
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode *next) : val(x), next(next) {}
};

// 迭代
class Solution 
{
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) 
    {
        // 申请哨兵位头结点，避免判空操作
        ListNode* newHead = new ListNode, *tail = newHead;
        ListNode* cur1 = l1, *cur2 = l2;
        int carry = 0; // 进位信息
        // 有一个不是空节点，或者还有进位，就继续迭代
        while(cur1 || cur2 || carry)
        {
            int val1 = cur1 ? cur1->val : 0;
            int val2 = cur2 ? cur2->val : 0;
            carry += val1 + val2; // 节点值和进位加在一起
            ListNode* newNode = new ListNode(carry % 10); // 每个节点保存一个数位
            tail->next = newNode;
            tail = newNode;
            carry /= 10; // 新的进位
            if(cur1) cur1 = cur1->next; // 下一个节点
            if(cur2) cur2 = cur2->next; // 下一个节点
        }

        // 哨兵位头节点的下一个节点就是头节点
        cur1 = newHead->next; // 保存结果
        delete newHead; // 释放哨兵位头节点的内存
        return cur1; // 返回结果
        
        // 注：可以直接返回 newHead->next
        // return newHead->next;
    }
};


// 递归
class Solution 
{
public:
    // l1 和 l2 为当前遍历的节点，carry 为进位
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2, int carry = 0) 
    {
        // 递归边界：l1 和 l2 都是空节点 
        if(!l1 && !l2) 
            return carry ? new ListNode(carry) : nullptr; // 如果进位了，就额外创建一个节点

        // 如果 l1 是空的，那么此时 l2 一定不是空节点
        if(l1 == nullptr) swap(l1, l2); // 交换 l1 与 l2，保证 l1 非空，从而简化代码
        carry += l1->val + (l2 ? l2->val : 0); // 节点值和进位加在一起
        l1->val = carry % 10; // 每个节点保存一个数位
        l1->next = addTwoNumbers(l1->next, (l2 ? l2->next : nullptr), carry / 10); // 进位
        return l1;
    }
};